#include <iostream>
#include <functional>
#include <memory>
#include "TcpServer.hpp"
#include "Protocol.hpp"
#include "CalCulate.hpp"

using namespace protocol_ns;

void Usage(std::string proc)
{
    std::cout << "Usage\n\t" << proc << " local_port\n"
              << std::endl;
}

// 服务器接收请求，返回应答
using callback_t = std::function<Response(const Request &req)>;

class Service
{
public:
    Service(callback_t cb)
        : _cb(cb)
    {
    }

    // 开始处理任务
    void ServiceHelper(socket_sptr sockptr, InetAddr client)
    {
        int sockfd = sockptr->SockFd();

        LOG(DEBUG, "get a new link, info %s:%d , fd: %d\n", client.Ip().c_str(), client.Port(), sockfd);

        std::string clientaddr = "[" + client.Ip() + ":" + std::to_string(client.Port()) + "]";
        std::string inbuffer;

        while (true)
        {
            sleep(5);

            Request req;

            // 1、接收报文
            int n = sockptr->Recv(&inbuffer);
            if (n < 0)
            {
                LOG(DEBUG, "client %s quit ... \n", clientaddr.c_str());
                break;
            }

            // 2、处理请求报文，确认是完整的报文
            std::string package;
            while (true)
            {
                sleep(1);
                std::cout << "inbuffer: " << inbuffer << std::endl;
                // 2.1 取出有效载荷
                package = Decode(inbuffer);

                // 不是完整报文，跳出本层循环，继续接收报文
                if (package.empty())
                    break;

                std::cout << "----------------begin----------------" << std::endl;
                std::cout << "resq string:\n"
                          << package << std::endl;

                // 一定是完整报文
                //  2.2 反序列化
                req.Deserialize(package);

                // 3、应答报文
                // 业务处理，得到应答报文
                Response resp = _cb(req);

                // 3.1 序列化
                std::string send_str;
                resp.Serialize(&send_str);

                std::cout << "resp Serialize: " << std::endl;
                std::cout << send_str << std::endl;

                // 3.2 加报头
                send_str = Encode(send_str);

                std::cout << "resp Encode: " << std::endl;
                std::cout << send_str << std::endl;

                // 发送应答报文
                sockptr->Send(send_str);
            }
        }
    }

private:
    callback_t _cb;
};

int main(int argc, char *argv[])
{
    if (argc != 2)
    {
        Usage(argv[0]);
        return 1;
    }

    uint16_t port = std::stoi(argv[1]);

    EnableScreen();

    Calculate cal;

    // 任务（数据），把 Calculate 和 协议关联起来
    Service calservice(std::bind(&Calculate::Excute, &cal, std::placeholders::_1));

    // 实例化服务
    io_service_t service = std::bind(&Service::ServiceHelper, &calservice, std::placeholders::_1, std::placeholders::_2);

    // 把服务交给服务器，用多线程处理
    std::unique_ptr<TcpServer> tsvr = std::make_unique<TcpServer>(port, service);

    // 启动服务
    tsvr->Loop();

    return 0;
}